package com.report.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.report.constant.MappingConstant;
import com.report.entity.AccountingProjectBalance;
import com.report.entity.AccountingProjectDetail;
import com.report.entity.SubjectBalance;
import com.report.entity.Voucher;
import com.report.enumeration.AccountCodeTypeEnum;
import com.report.repository.AccountingProjectBalanceRepository;
import com.report.repository.AccountingProjectDetailRepository;
import com.report.repository.SubjectBalanceRepository;
import com.report.repository.VoucherRepository;
import com.report.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Slf4j
@Service
public class BalanceService {

    @Resource
    private AccountingProjectDetailRepository accountingProjectDetailRepository;
    @Resource
    private AccountingProjectBalanceRepository accountingProjectBalanceRepository;
    @Resource
    private SubjectBalanceRepository subjectBalanceRepository;
    @Resource
    private VoucherRepository voucherRepository;
    @Value("${minio.domainName}")
    private String domainName;


    @Transactional
    public void syncData(BalanceSyncReq balanceSyncReq) {
        if (balanceSyncReq.getFileName().contains(MappingConstant.VOUCHER_TABLE)) {
            voucherRepository.deleteAllByProjectNoAndAuditCompanyUscc(balanceSyncReq.getProjectNo(), balanceSyncReq.getAuditCompanyUscc());
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.SUBJECT_BALANCE_TABLE)) {
            subjectBalanceRepository.deleteAllByProjectNoAndAuditCompanyUscc(balanceSyncReq.getProjectNo(), balanceSyncReq.getAuditCompanyUscc());
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_DETAIL_TABLE)) {
            accountingProjectDetailRepository.deleteAllByProjectNoAndAuditCompanyUscc(balanceSyncReq.getProjectNo(), balanceSyncReq.getAuditCompanyUscc());
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_BALANCE_TABLE)) {
            accountingProjectBalanceRepository.deleteAllByProjectNoAndAuditCompanyUscc(balanceSyncReq.getProjectNo(), balanceSyncReq.getAuditCompanyUscc());
        }
        //数据
        List list = new ArrayList<>();
        byte[] fileBytes = HttpUtil.downloadBytes(domainName + balanceSyncReq.getFileName());
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(fileBytes), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                handleLine(line, balanceSyncReq, list);
                //批量保存
                if (list.size() == 50) {
                    save(balanceSyncReq, list);
                    list.clear();
                }
            }
        } catch (IOException e) {
            log.error("{}同步数据失败", JSON.toJSONString(balanceSyncReq), e);
        } finally {
            save(balanceSyncReq, list);
        }
    }


    private void handleLine(String line, BalanceSyncReq balanceSyncReq, List list) {
        if (balanceSyncReq.getFileName().contains(MappingConstant.VOUCHER_TABLE)) {
            Map<String, String> maps = MappingConstant.mappings().get(MappingConstant.VOUCHER_TABLE);
            for (Map.Entry<String, String> map : maps.entrySet()) {
                line = line.replaceAll(map.getKey(), map.getValue());
            }
            Voucher voucher = JSON.parseObject(line, Voucher.class);
            voucher.setId(null);
            voucher.setProjectNo(balanceSyncReq.getProjectNo());
            voucher.setAuditCompanyUscc(balanceSyncReq.getAuditCompanyUscc());
            list.add(voucher);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.SUBJECT_BALANCE_TABLE)) {
            Map<String, String> maps = MappingConstant.mappings().get(MappingConstant.SUBJECT_BALANCE_TABLE);
            for (Map.Entry<String, String> map : maps.entrySet()) {
                line = line.replaceAll(map.getKey(), map.getValue());
            }
            SubjectBalance subjectBalance = JSON.parseObject(line, SubjectBalance.class);
            subjectBalance.setId(null);
            subjectBalance.setProjectNo(balanceSyncReq.getProjectNo());
            subjectBalance.setAuditCompanyUscc(balanceSyncReq.getAuditCompanyUscc());
            list.add(subjectBalance);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_DETAIL_TABLE)) {
            Map<String, String> maps = MappingConstant.mappings().get(MappingConstant.ACCOUNTING_PROJECT_DETAIL_TABLE);
            for (Map.Entry<String, String> map : maps.entrySet()) {
                line = line.replaceAll(map.getKey(), map.getValue());
            }
            AccountingProjectDetail accountingProjectDetail = JSON.parseObject(line, AccountingProjectDetail.class);
            accountingProjectDetail.setId(null);
            accountingProjectDetail.setProjectNo(balanceSyncReq.getProjectNo());
            accountingProjectDetail.setAuditCompanyUscc(balanceSyncReq.getAuditCompanyUscc());
            list.add(accountingProjectDetail);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_BALANCE_TABLE)) {
            Map<String, String> maps = MappingConstant.mappings().get(MappingConstant.ACCOUNTING_PROJECT_BALANCE_TABLE);
            for (Map.Entry<String, String> map : maps.entrySet()) {
                line = line.replaceAll(map.getKey(), map.getValue());
            }
            AccountingProjectBalance accountingProjectBalance = JSON.parseObject(line, AccountingProjectBalance.class);
            accountingProjectBalance.setId(null);
            accountingProjectBalance.setProjectNo(balanceSyncReq.getProjectNo());
            accountingProjectBalance.setAuditCompanyUscc(balanceSyncReq.getAuditCompanyUscc());
            list.add(accountingProjectBalance);
        }
    }


    public void save(BalanceSyncReq balanceSyncReq, List list) {
        if (balanceSyncReq.getFileName().contains(MappingConstant.VOUCHER_TABLE)) {
            voucherRepository.saveAllAndFlush(list);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.SUBJECT_BALANCE_TABLE)) {
            subjectBalanceRepository.saveAllAndFlush(list);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_DETAIL_TABLE)) {
            accountingProjectDetailRepository.saveAllAndFlush(list);
        } else if (balanceSyncReq.getFileName().contains(MappingConstant.ACCOUNTING_PROJECT_BALANCE_TABLE)) {
            accountingProjectBalanceRepository.saveAllAndFlush(list);
        }
    }

    /**
     * 获取科目余额列表
     *
     * @param balanceReq
     * @return
     * @see AccountCodeTypeEnum#ACCOUNT_CODE
     */
    public List<SubjectBalanceResVo> getSubjectBalances(BalanceReq balanceReq) {
        List<SubjectBalanceResVo> subjectBalanceResVos = new ArrayList<>();
        //一级科目
        List<SubjectBalance> subjectBalanceList = subjectBalanceRepository.findByAccountLevelAndAuditCompanyUscc("1", balanceReq.getAuditCompanyUscc());
        //List<SubjectBalance> subjectBalanceList = subjectBalanceRepository.findByAccountLevelAndAccountAndAuditCompanyUscc("1", "1123", balanceReq.getAuditCompanyUscc());

        subjectBalanceList.forEach(subjectBalance -> {
            SubjectBalanceResVo subjectBalanceResVo = Convert.convert(SubjectBalanceResVo.class, subjectBalance);
            subjectBalanceResVo.setLevel("1");
            subjectBalanceResVo.setAccountCodeType(AccountCodeTypeEnum.ACCOUNT_CODE.getCode());
            subjectBalanceResVos.add(subjectBalanceResVo);
        });
        //子级科目（2~3级）
        subjectBalanceResVos.forEach(subjectBalanceResVo -> {
            //查询所有子级科目
            List<SubjectBalance> accountList = subjectBalanceRepository.findByAccountCode(subjectBalanceResVo.getAccountCode(), balanceReq.getAuditCompanyUscc());
            //转换
            List<SubjectBalanceResVo> subjectBalanceResVoArrayList = Convert.toList(SubjectBalanceResVo.class, accountList);
            //分组
            Map<String, List<SubjectBalanceResVo>> levelMap = subjectBalanceResVoArrayList.stream().collect(Collectors.groupingBy(SubjectBalanceResVo::getAccountLevel));
            //构建树形结构
            List<SubjectBalanceResVo> children = subjectBalanceResVoArrayList.stream().peek(node -> {
                        if (Integer.parseInt(node.getAccountLevel()) > 2) {
                            int parentLevel = Integer.parseInt(node.getAccountLevel()) - 1;
                            levelMap.getOrDefault(String.valueOf(parentLevel), new ArrayList<>())
                                    .stream()
                                    .filter(parent -> node.getAccountCode().startsWith(parent.getAccountCode()))
                                    .findAny()
                                    .ifPresent(parent -> parent.getChildren().add(node));
                        }
                    })
                    .filter(node -> Integer.parseInt(node.getAccountLevel()) == 2)
                    .collect(Collectors.toList());
            subjectBalanceResVo.getChildren().addAll(children);
        });

        //计算数据
        calculate(subjectBalanceResVos, balanceReq, null);

        return subjectBalanceResVos;
    }

    public void calculate(List<SubjectBalanceResVo> subjectBalanceResVos, BalanceReq balanceReq, Integer parentLevel) {
        for (SubjectBalanceResVo subjectBalanceResVo : subjectBalanceResVos) {
            if (parentLevel != null) {
                subjectBalanceResVo.setLevel(String.valueOf(parentLevel));
            }
            if (CollectionUtil.isEmpty(subjectBalanceResVo.getChildren())) {
                calculateProjectTypeCode(subjectBalanceResVo, balanceReq);
                continue;
            }
            calculate(subjectBalanceResVo.getChildren(), balanceReq, Integer.parseInt(subjectBalanceResVo.getLevel()) + 1);
            calculateAmount(subjectBalanceResVo);
        }
    }


    /**
     * 计算
     *
     * @param balanceResVoTwoLevel
     * @param balanceReq
     * @see com.report.enumeration.AccountCodeTypeEnum#PROJECT_TYPE_CODE
     */
    public void calculateProjectTypeCode(SubjectBalanceResVo balanceResVoTwoLevel, BalanceReq balanceReq) {
        balanceResVoTwoLevel.setAccountCodeType(AccountCodeTypeEnum.ACCOUNT_CODE.getCode());
        //三级科目
        List<AccountingProjectBalance> accountingProjectBalanceList = accountingProjectBalanceRepository.findByAccountCodeAndAuditCompanyUscc(balanceResVoTwoLevel.getAccountCode(), balanceReq.getAuditCompanyUscc());
        Map<String, List<AccountingProjectBalance>> projectTypeCodes = accountingProjectBalanceList.stream().collect(Collectors.groupingBy(AccountingProjectBalance::getProjectTypeCode));

        for (Map.Entry<String, List<AccountingProjectBalance>> entry : projectTypeCodes.entrySet()) {
            SubjectBalanceResVo resVoThreeLevel = new SubjectBalanceResVo();
            resVoThreeLevel.setLevel(String.valueOf(Integer.parseInt(balanceResVoTwoLevel.getLevel()) + 1));
            resVoThreeLevel.setAccountCode(entry.getKey());
            resVoThreeLevel.setAccountName("[辅]" + entry.getValue().get(0).getProjectTypeName());
            resVoThreeLevel.setAccountCodeType(AccountCodeTypeEnum.PROJECT_TYPE_CODE.getCode());
            resVoThreeLevel.getChildren().addAll(calculateProjectCode(balanceReq, Integer.parseInt(resVoThreeLevel.getLevel()), entry.getValue()));

            calculateAmount(resVoThreeLevel);
            balanceResVoTwoLevel.getChildren().add(resVoThreeLevel);
        }
        calculateAmount(balanceResVoTwoLevel);
    }

    /**
     * 计算
     *
     * @param balanceReq
     * @param level
     * @param accountingProjectBalanceList
     * @return
     * @see AccountCodeTypeEnum#PROJECT_CODE
     */
    public List<SubjectBalanceResVo> calculateProjectCode(BalanceReq balanceReq, int level, List<AccountingProjectBalance> accountingProjectBalanceList) {

        // 使用 toMap 收集器进行合并
        Map<String, AccountingProjectBalance> uniqueBalances = accountingProjectBalanceList.stream()
                .peek(balance -> {
                    if (balance.getOpeningCreditAmount() == null) balance.setOpeningCreditAmount(BigDecimal.ZERO);
                    if (balance.getOpeningDebitAmount() == null) balance.setOpeningDebitAmount(BigDecimal.ZERO);
                })
                .collect(Collectors.toMap(
                        AccountingProjectBalance::getProjectCode,
                        Function.identity(),
                        (existing, replacement) -> {
                            // 合并 debitAmount 和 creditAmount
                            existing.setOpeningDebitAmount(existing.getOpeningDebitAmount().add(replacement.getOpeningDebitAmount()));
                            existing.setOpeningCreditAmount(existing.getOpeningCreditAmount().add(replacement.getOpeningCreditAmount()));
                            return existing;
                        }
                ));

        List<SubjectBalanceResVo> list = new ArrayList<>();

        for (Map.Entry<String, AccountingProjectBalance> entry : uniqueBalances.entrySet()) {

            AccountingProjectBalance accountingProjectBalance = entry.getValue();
            List<Map<String, Object>> amounts = accountingProjectDetailRepository.countAmount(accountingProjectBalance.getAccountCode(), accountingProjectBalance.getProjectCode(), accountingProjectBalance.getProjectTypeCode(), balanceReq.getAuditCompanyUscc());

            SubjectBalanceResVo subjectBalanceFourLevel = new SubjectBalanceResVo();
            subjectBalanceFourLevel.setLevel(String.valueOf(level + 1));
            subjectBalanceFourLevel.setAccountCode(accountingProjectBalance.getProjectCode());
            subjectBalanceFourLevel.setAccountName("[辅]" + accountingProjectBalance.getProjectName());
            subjectBalanceFourLevel.setSubjectDirection(accountingProjectBalance.getDebitCreditDirection());
            subjectBalanceFourLevel.setDebitAmount(new BigDecimal(amounts.get(0).get("debitAmount").toString()));
            subjectBalanceFourLevel.setCreditAmount(new BigDecimal(amounts.get(0).get("creditAmount").toString()));
            subjectBalanceFourLevel.setOpeningDebitAmount(accountingProjectBalance.getOpeningDebitAmount());
            subjectBalanceFourLevel.setClosingAmount(subjectBalanceFourLevel.getOpeningDebitAmount().add(subjectBalanceFourLevel.getDebitAmount()).subtract(subjectBalanceFourLevel.getCreditAmount()));
            subjectBalanceFourLevel.setAccountCodeType(AccountCodeTypeEnum.PROJECT_CODE.getCode());

            list.add(subjectBalanceFourLevel);
        }
        return list;
    }


    public void calculateAmount(SubjectBalanceResVo resVo) {
        resVo.getChildren().sort(Comparator.comparing(SubjectBalanceResVo::getAccountCode));

        resVo.setOpeningDebitAmount(resVo.getChildren().stream().map(SubjectBalanceResVo::getOpeningDebitAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        resVo.setDebitAmount(resVo.getChildren().stream().map(SubjectBalanceResVo::getDebitAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        resVo.setCreditAmount(resVo.getChildren().stream().map(SubjectBalanceResVo::getCreditAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        resVo.setClosingAmount(resVo.getChildren().stream().map(SubjectBalanceResVo::getClosingAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
    }

    public List<AccountingProjectDetailRespVo> getSubjectBalanceDetails(BalanceReq balanceReq) {

        if (balanceReq.getAccountCodeType() != AccountCodeTypeEnum.ACCOUNT_CODE.getCode()) {
            return null;
        }
        //查询明细
        List<AccountingProjectDetail> accountingProjectDetails = accountingProjectDetailRepository.findByAccountCodeAndAuditCompanyUscc(balanceReq.getAccountCode(), balanceReq.getAuditCompanyUscc());
        //拼装科目名称
        String accountCode = balanceReq.getAccountCode().substring(0, 4);
        Map<String, SubjectBalance> collects = subjectBalanceRepository.findByAccountCode(accountCode, balanceReq.getAuditCompanyUscc()).stream().collect(Collectors.toMap(SubjectBalance::getAccountCode, subjectBalance -> subjectBalance));
        //获取科目名称
        Map<String, String> codeName = getAccountName(collects);


        List<AccountingProjectDetailRespVo> accountingProjectDetailRespVos = new ArrayList<>();
        //承前余额
        BigDecimal openingDebitAmount = collects.get(balanceReq.getAccountCode()).getOpeningDebitAmount();
        //承前数据
        AccountingProjectDetailRespVo detailRespVo = new AccountingProjectDetailRespVo();
        detailRespVo.setSummary("承前");
        detailRespVo.setAccountName(codeName.get(balanceReq.getAccountCode()));
        detailRespVo.setBalance(openingDebitAmount);
        accountingProjectDetailRespVos.add(detailRespVo);

        for (AccountingProjectDetail accountingProjectDetail : accountingProjectDetails) {
            AccountingProjectDetailRespVo accountingProjectDetailRespVo = Convert.convert(AccountingProjectDetailRespVo.class, accountingProjectDetail);
            accountingProjectDetailRespVo.setAccountName(codeName.get(accountingProjectDetail.getAccountCode()));
            accountingProjectDetailRespVo.setProjectTypeName("【" + accountingProjectDetail.getProjectTypeName() + ":" + accountingProjectDetail.getProjectName() + "】");

            BigDecimal debitAmount = accountingProjectDetailRespVo.getDebitAmount();
            if (debitAmount != null) {
                openingDebitAmount = openingDebitAmount.add(debitAmount);
            }
            BigDecimal creditAmount = accountingProjectDetailRespVo.getCreditAmount();
            if (creditAmount != null) {
                openingDebitAmount = openingDebitAmount.subtract(creditAmount);
            }
            //余额
            accountingProjectDetailRespVo.setBalance(openingDebitAmount);
            //一级、末级文本处理
            StringBuilder text = new StringBuilder();
            List<Voucher> byVoucher = voucherRepository.findByVoucherNumberAndVoucherDate(accountingProjectDetail.getVoucherNumber(), accountingProjectDetail.getVoucherDate());
            if (CollectionUtil.isNotEmpty(byVoucher)) {
                byVoucher = byVoucher.stream().filter(voucher -> !voucher.getAccountCode().equals(accountingProjectDetail.getAccountCode())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(byVoucher)) {
                    for (Voucher voucher : byVoucher) {
                        List<String> accountCodes = new ArrayList<>();
                        accountCodes.add(voucher.getAccountCode());
                        //每次截掉后三位
                        while (voucher.getAccountCode().length() > 4) {
                            voucher.setAccountCode(voucher.getAccountCode().substring(0, voucher.getAccountCode().length() - 3));
                            accountCodes.add(voucher.getAccountCode());
                        }
                        String accountName = subjectBalanceRepository.findAccountName(accountCodes, balanceReq.getAuditCompanyUscc());
                        String amount = voucher.getCreditAmount() == null || voucher.getCreditAmount().compareTo(BigDecimal.ZERO) < 1 ? "" : voucher.getDebitAmount().toString();
                        text.append(accountName)
                                .append("{【").append(accountingProjectDetail.getProjectTypeName()).append(":").append(extractMaxChineseSequence(accountingProjectDetail.getSummary())).append("】}")
                                .append("【").append(amount).append("】")
                                .append("\r\n");
                    }
                }
            }
            accountingProjectDetailRespVo.setDirection("借");
            accountingProjectDetailRespVo.setLevel1(text.toString());
            accountingProjectDetailRespVo.setFinallyLevel(text.toString());
            accountingProjectDetailRespVos.add(accountingProjectDetailRespVo);
        }

        return accountingProjectDetailRespVos;
    }

    /**
     * 获取科目名字列表（带父级别的科目）
     *
     * @param collects
     * @return
     */
    public Map<String, String> getAccountName(Map<String, SubjectBalance> collects) {
        //拼装科目名称
        Map<String, String> codeName = new HashMap<>();
        for (Map.Entry<String, SubjectBalance> entry : collects.entrySet()) {
            SubjectBalance subjectBalance = entry.getValue();

            ArrayList<String> accountNames = new ArrayList<>();
            accountNames.add(subjectBalance.getAccountName());

            if (!subjectBalance.getAccountLevel().equals("1")) {
                int level = Integer.parseInt(subjectBalance.getAccountLevel());
                String key = entry.getKey();
                for (int i = 0; i < level - 1; i++) {
                    key = key.substring(0, key.length() - 1 - 2);
                    String accountName = collects.get(key).getAccountName();
                    accountNames.add(accountName);
                }
                Collections.reverse(accountNames);
            }

            codeName.put(entry.getKey(), String.join("-", accountNames));
        }
        return codeName;
    }


    public String extractMaxChineseSequence(String input) {
        if (input == null || input.isEmpty()) {
            return "";
        }

        // 使用正则表达式匹配所有连续的汉字序列
        Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
        Matcher matcher = pattern.matcher(input);

        String maxSequence = "";
        while (matcher.find()) {
            String currentSequence = matcher.group();
            if (currentSequence.length() > maxSequence.length()) {
                maxSequence = currentSequence;
            }
        }

        return maxSequence;
    }

    public List<AccountingProjectBalanceDetailRespVo> getAccountingProjectDetails(BalanceReq balanceReq) {

        List<AccountingProjectDetail> accountingProjectDetails = new ArrayList<>();
        BigDecimal openingDebitAmount = BigDecimal.ZERO;
        if (balanceReq.getAccountCodeType() == AccountCodeTypeEnum.PROJECT_TYPE_CODE.getCode()) {
            accountingProjectDetails = accountingProjectDetailRepository.findByProjectTypeCodeAndAuditCompanyUsccOrderByVoucherDateVoucherNumber(balanceReq.getAccountCode(), balanceReq.getAuditCompanyUscc());
            //计算承前金额
            String amount = accountingProjectBalanceRepository.calculateAmountByProjectTypeCode(balanceReq.getAccountCode(), balanceReq.getParentAccountCode(), balanceReq.getAuditCompanyUscc());
            openingDebitAmount = new BigDecimal(amount);
        } else if (balanceReq.getAccountCodeType() == AccountCodeTypeEnum.PROJECT_CODE.getCode()) {
            accountingProjectDetails = accountingProjectDetailRepository.findByProjectCodeAndAuditCompanyUsccOrderByVoucherDateVoucherNumber(balanceReq.getAccountCode(), balanceReq.getAuditCompanyUscc());
            //计算承前金额
            String amount = accountingProjectBalanceRepository.calculateAmountByProjectCode(balanceReq.getAccountCode(), balanceReq.getParentAccountCode(), balanceReq.getAuditCompanyUscc());
            openingDebitAmount = new BigDecimal(amount);
        } else {
            return null;
        }
        //拼装科目名称
        Map<String, SubjectBalance> collects = subjectBalanceRepository.findByAccountCode(balanceReq.getParentAccountCode().substring(0, 4), balanceReq.getAuditCompanyUscc()).stream().collect(Collectors.toMap(SubjectBalance::getAccountCode, subjectBalance -> subjectBalance));
        //获取科目名称
        String codeName = getAccountName(collects).get(balanceReq.getParentAccountCode());

        ArrayList<AccountingProjectBalanceDetailRespVo> detailRespVos = new ArrayList<>();
        //承前数据
        AccountingProjectBalanceDetailRespVo detailRespVo1 = new AccountingProjectBalanceDetailRespVo();
        detailRespVo1.setSummary("承前");
        detailRespVo1.setBalance(openingDebitAmount);
        detailRespVo1.setDirection("借");
        detailRespVos.add(detailRespVo1);
        for (AccountingProjectDetail accountingProjectDetail : accountingProjectDetails) {
            AccountingProjectBalanceDetailRespVo detailRespVo = Convert.convert(AccountingProjectBalanceDetailRespVo.class, accountingProjectDetail);

            BigDecimal debitAmount = accountingProjectDetail.getDebitAmount();
            if (debitAmount != null) {
                openingDebitAmount = openingDebitAmount.add(debitAmount);
            }
            BigDecimal creditAmount = accountingProjectDetail.getCreditAmount();
            if (creditAmount != null) {
                openingDebitAmount = openingDebitAmount.subtract(creditAmount);
            }
            //余额
            detailRespVo.setBalance(openingDebitAmount);

            List<Voucher> byVoucher = voucherRepository.findByVoucherNumberAndVoucherDate(accountingProjectDetail.getVoucherNumber(), accountingProjectDetail.getVoucherDate());
            if (CollectionUtil.isNotEmpty(byVoucher)) {
                //核算项目编号的不用过滤，直接用；核算项目类型编号需要过滤
                if (balanceReq.getAccountCodeType() == AccountCodeTypeEnum.PROJECT_TYPE_CODE.getCode()) {
                    byVoucher = byVoucher.stream().filter(voucher -> !voucher.getAccountCode().equals(accountingProjectDetail.getAccountCode())).collect(Collectors.toList());
                }

                if (CollectionUtil.isNotEmpty(byVoucher)) {
                    //TODO 是否会有多凭证，目前是一个凭证号，多条分录序号，所以取一条
                    String accountCode = byVoucher.get(0).getAccountCode().substring(0, 4);
                    String accountName = subjectBalanceRepository.findAccountName(Arrays.asList(accountCode), balanceReq.getAuditCompanyUscc());

                    String amount = accountingProjectDetail.getDebitAmount() == null || accountingProjectDetail.getDebitAmount().compareTo(BigDecimal.ZERO) < 1 ? accountingProjectDetail.getCreditAmount().toString() : accountingProjectDetail.getDebitAmount().toString();
                    detailRespVo.setOtherAccountName(accountName + "【" + amount + "】");
                }
            }
            detailRespVo.setAccountName(codeName);
            detailRespVo.setDirection("借");
            detailRespVos.add(detailRespVo);
        }

        return detailRespVos;
    }

    public List<VoucherRespVo> getVouchers(BalanceReq balanceReq) throws ParseException {
        List<VoucherRespVo> voucherRespVos1 = new ArrayList<>();
        List<AccountingProjectDetail> accountingProjectDetails = accountingProjectDetailRepository.findByVoucherDateAndVoucherNumberAndAuditCompanyUscc(DateUtils.parseDate(balanceReq.getVoucherDate(), "yyyy-MM-dd"), balanceReq.getVoucherNumber(), balanceReq.getAuditCompanyUscc());
        for (AccountingProjectDetail accountingProjectDetail : accountingProjectDetails) {
            VoucherRespVo voucherRespVo = Convert.convert(VoucherRespVo.class, accountingProjectDetail);
            //拼装科目名称
            Map<String, SubjectBalance> collects = subjectBalanceRepository.findByAccountCode(accountingProjectDetail.getAccountCode().substring(0, 4), balanceReq.getAuditCompanyUscc()).stream().collect(Collectors.toMap(SubjectBalance::getAccountCode, subjectBalance -> subjectBalance));
            //获取科目名称
            String codeName = getAccountName(collects).get(accountingProjectDetail.getAccountCode());
            voucherRespVo.setAccountName(codeName);
            voucherRespVo.setProjectName("【" + accountingProjectDetail.getProjectTypeName() + ":" + accountingProjectDetail.getProjectName() + "】");
            voucherRespVo.setType(0);
            voucherRespVos1.add(voucherRespVo);
        }
        voucherRespVos1.stream().forEach(voucherRespVo -> {
            List<VoucherRespVo> collects = voucherRespVos1.stream().filter(voucherRespVo1 -> !voucherRespVo1.getAccountCode().equals(voucherRespVo.getAccountCode())).collect(Collectors.toList());
            StringBuilder text = new StringBuilder();
            for (VoucherRespVo collect : collects) {
                String amount = collect.getDebitAmount() == null || collect.getDebitAmount().compareTo(BigDecimal.ZERO) < 1 ? collect.getCreditAmount().toString() : collect.getDebitAmount().toString();
                text.append(collect.getAccountName() + "{" + collect.getProjectName() + "}").append("【" + amount + "】").append("\r\n");
            }
            voucherRespVo.setOtherAccountName(text.toString());
        });


        List<VoucherRespVo> voucherRespVos2 = new ArrayList<>();
        List<Voucher> vouchers = voucherRepository.findByVoucherNumberAndVoucherDate(balanceReq.getVoucherNumber(), DateUtils.parseDate(balanceReq.getVoucherDate(), "yyyy-MM-dd"));
        for (Voucher voucher : vouchers) {
            VoucherRespVo voucherRespVo = Convert.convert(VoucherRespVo.class, voucher);

            //拼装科目名称
            Map<String, SubjectBalance> collects = subjectBalanceRepository.findByAccountCode(voucher.getAccountCode().substring(0, 4), balanceReq.getAuditCompanyUscc()).stream().collect(Collectors.toMap(SubjectBalance::getAccountCode, subjectBalance -> subjectBalance));
            //获取科目名称
            String codeName = getAccountName(collects).get(voucher.getAccountCode());
            voucherRespVo.setAccountName(codeName);
            voucherRespVo.setType(1);
            voucherRespVos2.add(voucherRespVo);
        }

        voucherRespVos1.addAll(voucherRespVos2);
        return voucherRespVos1;
    }
}
